#!perl
sub upperc {
    local($_) = pop(@_);
    tr/[a-z]/[A-Z]/;
    return $_;
}

&output_header;

&arith_insn("add", "i u ul l p", "arm_dproc", "ADD", "0");
&arith_insn("sub", "i u ul l p", "arm_dproc", "SUB", "0");
&arith_insn("mul", "u ul", "arm_mul", "1", "0");
&arith_insn("mul", "i l", "arm_mul", "0", "0");
&arith_insn("div", "u ul", "arm_div", "1", 0);
&arith_insn("div", "i l", "arm_div", "0", 0);
&arith_insn("mod", "u", "arm_mod", "0x0/*umod*/", 0); #"FORM3(2,0x0,dest,src1,src2)", 
&arith_insn("mod", "ul", "arm_mod", "0x0/*umod*/", 1); #"FORM3(2,0x0,dest,src1,src2)", 
&arith_insn("mod", "i", "arm_mod", "0x1/*smod*/", 0); #"FORM3(2,0x0,dest,src1,src2)", 
&arith_insn("mod", "l", "arm_mod", "0x1/*smod*/", 1); #"FORM3(2,0x0,dest,src1,src2)", 
&arith_insn("and", "i u ul l", "arm_dproc", "AND", "0");
&arith_insn("or", "i u ul l", "arm_dproc", "ORR", "0");
&arith_insn("xor", "i u ul l", "arm_dproc", "EOR", "0");
&arith2_insn("com", "i u ul l", "(arith_op2)arm_dproc2", "MVN", "2");
&arith2_insn("neg", "i u ul l", "(arith_op2)arm_dproc2", "RSB", "2");
&arith2_insn("not", "i u ul l", "(arith_op2)arm_dproc2", "CMN", "0");
&arith_insn("lsh", "i u ul l", "arm_dproc", "MOV", LLshift);
&arith_insn("rsh", "i l", "arm_dproc", "MOV", ARshift);
&arith_insn("rsh", "u ul", "arm_dproc", "MOV", LRshift);
&arith_insn("add", "f", "arm_fproc", "0x0", "0x0");
&arith_insn("add", "d", "arm_fproc", "0x0", "0x1");
&arith_insn("sub", "f", "arm_fproc", "0x4", "0x0");
&arith_insn("sub", "d", "arm_fproc", "0x4", "0x1");
&arith_insn("mul", "f", "arm_fproc", "0x2", "0x0");
&arith_insn("mul", "d", "arm_fproc", "0x2", "0x1");
&arith_insn("div", "f", "arm_fproc", "0x8", "0x0");
&arith_insn("div", "d", "arm_fproc", "0x8", "0x1");
&arith2_insn("neg", "f", "arm_fproc2", "0x3", "0x0");
&arith2_insn("neg", "d", "arm_fproc2", "0x3", "0x1");

&arithi_insn("add", "i u ul l p", "arm_dproci", "ADD", "0");
&arithi_insn("sub", "i u ul l p", "arm_dproci", "SUB", "0");
&arithi_insn("mul", "u ul", "arm_muli", "1", "0");
&arithi_insn("mul", "i l", "arm_muli", "0", "0");
&arithi_insn("div", "u ul", "arm_divi", "1", "0");
&arithi_insn("div", "i l", "arm_divi", "0", "0");
&arithi_insn("mod", "u ul", "arm_modi", "0", "0");
&arithi_insn("mod", "i l", "arm_modi", "1", "0");
&arithi_insn("and", "i u ul l", "arm_dproci", "AND", "0");
&arithi_insn("or", "i u ul l", "arm_dproci", "ORR", "0");
&arithi_insn("xor", "i u ul l", "arm_dproci", "EOR", "0");
&arithi_insn("lsh", "i l u ul", "arm_dproci", "MOV", "LLshift");
&arithi_insn("rsh", "i l", "arm_dproci", "MOV", "ARshift");
&arithi_insn("rsh", "u ul", "arm_dproci", "MOV", "LRshift");
&branch_insn( "eq ge gt le lt ne", "i u ul l p d f", "arm_branch");
&branchi_insn( "eq ge gt le lt ne", "i u ul l p", "arm_branchi");

print COUT "jmp_table ${mach}_jump_table;\n";
print COUT "static void gen_arm_jump_table()\n";
print COUT "{\n";
print COUT "\t  ${mach}_jump_table = alloc_dill_jump_table();\n";
print COUT $jmp_a3_assigns;
print COUT $jmp_a3i_assigns;
print COUT $jmp_a2_assigns;
print COUT $jmp_b_assigns;
print COUT "\t  ${mach}_jump_table->proc_start = (dill_mach_proc_start) arm_proc_start;\n";
print COUT "\t  ${mach}_jump_table->end = arm_end;\n";
print COUT "\t  ${mach}_jump_table->type_align = arm_type_align;\n";
print COUT "\t  ${mach}_jump_table->type_size = arm_type_size;\n";
print COUT "\t  ${mach}_jump_table->clone_code = arm_clone_code;\n";
print COUT "\t  ${mach}_jump_table->ret = arm_ret;\n";
print COUT "\t  ${mach}_jump_table->reti = arm_reti;\n";
print COUT "\t  ${mach}_jump_table->retf = (ret_opf)arm_reti;\n";
print COUT "\t  ${mach}_jump_table->load = arm_pload;\n";
print COUT "\t  ${mach}_jump_table->bsload = arm_pbsload;\n";
print COUT "\t  ${mach}_jump_table->loadi = arm_ploadi;\n";
print COUT "\t  ${mach}_jump_table->bsloadi = arm_pbsloadi;\n";
print COUT "\t  ${mach}_jump_table->loadi = arm_ploadi;\n";
print COUT "\t  ${mach}_jump_table->store = arm_pstore;\n";
print COUT "\t  ${mach}_jump_table->storei = arm_pstorei;\n";
print COUT "\t  ${mach}_jump_table->convert = arm_convert;\n";
print COUT "\t  ${mach}_jump_table->mov = arm_mov;\n";
print COUT "\t  ${mach}_jump_table->set = arm_pset;\n";
print COUT "\t  ${mach}_jump_table->setf = arm_setf;\n";
print COUT "\t  ${mach}_jump_table->jv = arm_jump_to_label;\n";
print COUT "\t  ${mach}_jump_table->jp = arm_jump_to_reg;\n";
print COUT "\t  ${mach}_jump_table->jpi = arm_jump_to_imm;\n";
print COUT "\t  ${mach}_jump_table->jal = arm_jal;\n";
print COUT "\t  ${mach}_jump_table->push = arm_push;\n";
print COUT "\t  ${mach}_jump_table->pushi = arm_pushi;\n";
print COUT "\t  ${mach}_jump_table->pushfi = arm_pushfi;\n";
print COUT "\t  ${mach}_jump_table->pushpi = arm_pushpi;\n";
print COUT "\t  ${mach}_jump_table->calli = arm_calli;\n";
print COUT "\t  ${mach}_jump_table->callr = arm_callr;\n";
print COUT "\t  ${mach}_jump_table->local = arm_local_op;\n";
print COUT "\t  ${mach}_jump_table->save_restore = arm_save_restore_op;\n";
#print COUT "\t  ${mach}_jump_table->lea = arm_lea;\n";
print COUT "\t  ${mach}_jump_table->init_disassembly = arm_init_disassembly_info;\n";
print COUT "\t  ${mach}_jump_table->print_insn = arm_print_insn;\n";
print COUT "\t  ${mach}_jump_table->print_reg = arm_print_reg;\n";
print COUT "\t  ${mach}_jump_table->count_insn = arm_count_insn;\n";
print COUT "\t  ${mach}_jump_table->do_reverse_push = 0;\n";
print COUT "\t  ${mach}_jump_table->target_byte_order = 2;  /* Format_Integer_littleendian */\n";
print COUT "\t  ${mach}_jump_table->target_float_format = 3;  /* Format_IEEE_754_mixedendian */ \n";
print COUT "}\n\n";
print COUT "extern void dill_arm_init(dill_stream s)\n{\n";
print COUT "\tif(${mach}_jump_table == 0) {\n";
print COUT "\t  gen_arm_jump_table();\n";
print COUT "\t}\n";
print COUT "\ts->j = ${mach}_jump_table;\n";
print COUT "\ts->dill_local_pointer = _fp;\n";
print COUT "\ts->dill_param_reg_pointer = _fp;\n";
print COUT "\ts->p->mach_info = (void*)gen_arm_mach_info(s,/*v9*/ 0);\n";
print COUT "\ts->p->machine_strr_tmp_reg = _v1;\n";
print COUT "\treturn;\n";
print COUT "}\n";
print COUT "extern void dill_armv9_init(dill_stream s)\n{\n";
print COUT "\tif(${mach}_jump_table == 0) {\n";
print COUT "\t  gen_arm_jump_table();\n";
print COUT "\t}\n";
print COUT "\ts->j = ${mach}_jump_table;\n";
print COUT "\ts->dill_local_pointer = _fp;\n";
print COUT "\ts->dill_param_reg_pointer = _fp;\n";
print COUT "\ts->p->mach_info = (void*)gen_arm_mach_info(s,/*v9*/ 1);\n";
print COUT "\ts->p->machine_strr_tmp_reg = _v1;\n";
print COUT "\treturn;\n";
print COUT "}\n";

sub arith_insn {
    local ($op, $type_list, $subr, $code1, $code2) = @_;
    foreach(split(' ', $type_list)) {
	$jmp_a3_assigns = $jmp_a3_assigns . "\t  ${mach}_jump_table->jmp_a3[dill_jmp_${op}${_}] = $subr;\n";
	$jmp_a3_assigns = $jmp_a3_assigns . "\t  ${mach}_jump_table->a3_data[dill_jmp_${op}${_}].data1 = $code1;\n";
	$jmp_a3_assigns = $jmp_a3_assigns . "\t  ${mach}_jump_table->a3_data[dill_jmp_${op}${_}].data2 = $code2;\n";
    }
}

sub arith2_insn {
    local ($op, $type_list, $subr, $code1, $code2) = @_;
    foreach(split(' ', $type_list)) {
	$jmp_a2_assigns = $jmp_a2_assigns . "\t  ${mach}_jump_table->jmp_a2[dill_jmp_${op}${_}] = $subr;\n";
	$jmp_a2_assigns = $jmp_a2_assigns . "\t  ${mach}_jump_table->a2_data[dill_jmp_${op}${_}].data1 = $code1;\n";
	$jmp_a2_assigns = $jmp_a2_assigns . "\t  ${mach}_jump_table->a2_data[dill_jmp_${op}${_}].data2 = $code2;\n";
    }
}

sub arithi_insn {
    local ($op, $type_list, $subr, $code1, $code2) = @_;
    foreach(split(' ', $type_list)) {
	$jmp_a3i_assigns = $jmp_a3i_assigns . "\t  ${mach}_jump_table->jmp_a3i[dill_jmp_${op}${_}] = $subr;\n";
	$jmp_a3i_assigns = $jmp_a3i_assigns . "\t  ${mach}_jump_table->a3i_data[dill_jmp_${op}${_}].data1 = $code1;\n";
	$jmp_a3i_assigns = $jmp_a3i_assigns . "\t  ${mach}_jump_table->a3i_data[dill_jmp_${op}${_}].data2 = $code2;\n";
    }
}

sub branch_insn {
    local($ops, $types, $subr) = @_;
    foreach (split(' ', $ops)) {
	$op = $_;
	foreach (split(' ', $types)) {
	    $jmp_b_assigns = $jmp_b_assigns . "\t  ${mach}_jump_table->jmp_b[dill_jmp_b${op}${_}] = $subr;\n";
	    $jmp_b_assigns = $jmp_b_assigns . "\t  ${mach}_jump_table->b_data[dill_jmp_b${op}${_}].data1 = dill_${op}_code;\n";
	    $jmp_b_assigns = $jmp_b_assigns . "\t  ${mach}_jump_table->b_data[dill_jmp_b${op}${_}].data2 = DILL_". &upperc(${_}). ";\n";
	}
    }
}

sub branchi_insn {
    local($ops, $types, $subr) = @_;
    foreach (split(' ', $ops)) {
	$op = $_;
	foreach (split(' ', $types)) {
	    $jmp_b_assigns = $jmp_b_assigns . "\t  ${mach}_jump_table->jmp_bi[dill_jmp_b${op}${_}] = $subr;\n";
	}
    }
}

sub output_header {
    $mach = arm5;
    open(COUT, ">dill_${mach}.c") || die "Can't open header output";
print COUT<<EOF;
/* This file is generated from arm5.ops.  Do not edit directly. */

#include "dill.h"
#include "dill_internal.h"
#include "arm5.h"
EOF
}
